﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GridNewUtils.h"
#include "AlgorithmProject.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpDocUtils.h"
#include "GridNewCommon.h"
#include "GridNewInput.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IGenericElement.h"
#include "IGraphicsText.h"
#include "ILevel.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IPlane.h"
#include "IPresetParameterManager.h"
#include "LevelUtils.h"
#include "SingleGrid.h"
#include "Vector3dUtils.h"
#include <cwctype>

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

namespace
{
    std::wstring DeduceNum(const std::wstring& currNum)
    {
        std::wstring::size_type beg = currNum.find_first_not_of('0');
        if (beg == std::wstring::npos)
        {
            std::wstring temp = currNum;
            temp.back() = '1';
            return temp;
        }
        if (beg == 0)
        {
            return std::to_wstring(stoi(currNum) + 1);
        }
        std::wstring temp = std::to_wstring(stoi(currNum.substr(beg)) + 1);
        return currNum.substr(0, currNum.size() - temp.size()) + temp;
    }

    std::wstring DeduceAlpha(const wchar_t currAlpha)
    {
        if (currAlpha == 'Y' || currAlpha == 'Z')
        {
            return std::wstring(L"AA");
        }
        else if (currAlpha == 'y' || currAlpha == 'z')
        {
            return std::wstring(L"aa");
        }
        else {
            wchar_t temp = currAlpha + 1;
            if (temp == 'I' || temp == 'i' || temp == 'O' || temp == 'o')
            {
                temp = temp + 1;
            }
            return std::wstring(1, temp);
        }
        return std::wstring();
    }

    bool IsDigit(const wchar_t currChar)
    {
        return (currChar - '0') >= 0 && (currChar - '0') <= 9;
    }

    bool IsAlpha(const wchar_t currChar)
    {
        return ((currChar - 'a') >= 0 && (currChar - 'a') <= 25) || ((currChar - 'A') >= 0 && (currChar - 'A') <= 25);
    }

    bool IsValidGridChar(wchar_t ch)
    {
        static std::set<wchar_t> invalidCharSet;
        if (invalidCharSet.empty())
        {
            for (auto it = GridNewConstants::INVALID_NAME_CHARSET.begin(); it != GridNewConstants::INVALID_NAME_CHARSET.end(); ++it)
            {
                invalidCharSet.insert(*it);
            }
        }

        if (std::iswprint(ch) != 0)
        {
            if (invalidCharSet.find(ch) != invalidCharSet.end())
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        
        return false;
    }
}

bool gcmp::GridNewUtils::IsNameValid(const std::wstring& name)
{
    for (int i = 0; i < static_cast<int>(name.size()); ++i)
    {
        wchar_t ch = name[i];
        if (!IsValidGridChar(ch))
        {
            return false;
        }
    }
    return true;
}

bool gcmp::GridNewUtils::IsNameDuplicated(const IDocument* pDoc, const std::wstring& name)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空。",L"GDMPLab",L"2024-03-30");
    std::vector<IElement*> allGridElements = gcmp::GbmpDocUtils::GetElementsByCategory(pDoc, BuiltInCategoryUniIdentities::BICU_NEW_GRID);
    FOR_EACH(pGridElement, allGridElements)
    {
        const IGenericElement* pGenericGridElement = quick_cast<IGenericElement>(pGridElement);
        if (pGenericGridElement && !pGenericGridElement->GetBasicInformation()->GetIsTransient())
        {
            const SingleGrid* pGrid = quick_cast<SingleGrid>(pGenericGridElement->GetExternalObject());
            if (pGrid && (name == pGrid->GetName()))
            {
                return true;
            }
        }
    }

    return false;
}

bool gcmp::GridNewUtils::GetNextName(const std::wstring& currName, std::wstring& nextName)
{
    if (currName.empty())
    {
        return false;
    }

    for (std::wstring::size_type end = currName.size() - 1; end != std::string::npos; end--)
    {
        std::wstring::size_type beg = end;
        if (IsDigit(currName[end]))
        {
            while (beg - 1 != std::string::npos && IsDigit(currName[beg - 1]))
            {
                beg--;
            }
            nextName = currName.substr(0, beg) + DeduceNum(currName.substr(beg, end - beg + 1)) + currName.substr(end + 1);
            return true;
        }
        if (IsAlpha(currName[end]))
        {
            nextName = currName.substr(0, beg) + DeduceAlpha(currName[end]) + currName.substr(end + 1);
            return true;
        }
    }
    nextName = currName;
    return false;
}

gcmp::Intervald gcmp::GridNewUtils::GetGridDefaultVerticalExtents(const IDocument* pDoc, const IPlane * pPlane, ElementCreationOptions eco /*= ElementCreationOptions::Normal*/)
{
    DBG_WARN_AND_RETURN_UNLESS( pDoc&& pPlane, GridNewConstants::DEFAULT_VERTICAL_EXTENTS, L"Document为空",L"GDMPLab",L"2024-03-30");
    Intervald verticalExtents = GridNewConstants::DEFAULT_VERTICAL_EXTENTS;
    if (ElementCreationOptions::Normal == eco)
    {
        // 非临时类型的轴网，取项目内最低标高和最高标高为参考
        std::vector<const ILevel*> allLevels = LevelUtils::GetLevelsFromHighToLow(pDoc);
        if (!allLevels.empty())
        {
            const ILevel* pLowestLevel = *allLevels.rbegin();
            const ILevel* pHighestLevel = *allLevels.begin();
            DBG_WARN_AND_RETURN_UNLESS(pLowestLevel && pHighestLevel, GridNewConstants::DEFAULT_VERTICAL_EXTENTS, L"Level为空",L"GDMPLab",L"2024-03-30");
            verticalExtents = verticalExtents
                + Intervald::Create(pLowestLevel->GetElevation(), pHighestLevel->GetElevation());
        }
    }
    else if (ElementCreationOptions::Transient == eco)
    {
        // 临时类型的轴网，取工作平面包围盒为参考（加速）
        verticalExtents = verticalExtents
            + Intervald::Create(pPlane->GetBox().GetMinPoint().GetZ(), pPlane->GetBox().GetMaxPoint().GetZ());
    }
    return verticalExtents;
}

bool gcmp::GridNewUtils::setGridNewPresetParameter(const IDocument* pDoc,bool& startTagVisble, bool& endTagVisble)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pPresetParameterMgr为空",L"GDMPLab",L"2024-03-30");
    gcmp::UniIdentity categoryUid = BuiltInCategoryUniIdentities::BICU_NEW_GRID;

    IPresetParameterManager *pPresetParameterMgr = IPresetParameterManager::Get(pDoc);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pPresetParameterMgr, L"pPresetParameterMgr为空",L"GDMPLab",L"2024-03-30");

    //获取除了轴号的属性面板参数
    const IParameter* pParameter = nullptr;
    // 应用平面视图轴号端点1参数
    pParameter = pPresetParameterMgr->GetPresetParameter(categoryUid, 0, IParameterDefinitionLibrary::Get(pDoc)->GetParameterDefinitionIdByUid(PARAMETER_UID(GridStartTagVisibilityInPlanViewBuiltInParameter)));
    if (pParameter)
    {
        startTagVisble = pParameter->GetValueAsBool();
    }
    // 应用平面视图轴号端点2参数
    pParameter = pPresetParameterMgr->GetPresetParameter(categoryUid, 0, IParameterDefinitionLibrary::Get(pDoc)->GetParameterDefinitionIdByUid(PARAMETER_UID(GridEndTagVisibilityInPlanViewBuiltInParameter)));
    if (pParameter)
    {
        endTagVisble = pParameter->GetValueAsBool();
    }
    return true;

}

